package com.example.my_bookkeeping;


import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anything;
import static org.hamcrest.Matchers.is;

import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;
import androidx.test.espresso.DataInteraction;
import androidx.test.espresso.ViewInteraction;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;

import com.example.my_bookkeeping.data.manager.BookKeepManager;
import com.example.my_bookkeeping.data.manager.CategoryManager;
import com.example.my_bookkeeping.data.manager.UserManager;
import com.example.my_bookkeeping.ui.bookkeep.BookkeepFragment;
import com.example.my_bookkeeping.ui.category.CategoryFragment;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.Arrays;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class ShowCategoryTest {

    @Rule
    public ActivityScenarioRule<MainActivity> mActivityScenarioRule =
            new ActivityScenarioRule<>(MainActivity.class);

    private CategoryManager categoryManager;
    private UserManager userManager;

    @Before
    public void setup(){
        userManager = UserManager.getInstance();
        userManager.reset();
        BookKeepManager bookKeepManager = BookKeepManager.getInstance();
        bookKeepManager.add("2023-10-01", 100.0, "餐饮", "测试备注", false);
        bookKeepManager.add("2023-10-02", 200.0, "工资", "测试备注", true);
        bookKeepManager.add("2023-10-03", 300.0, "出行", "测试备注", false);
        bookKeepManager.add("2023-10-04", 400.0, "工资", "测试备注", true);
        bookKeepManager.add("2023-10-05", 500.0, "餐饮", "测试备注", false);
        bookKeepManager.add("2023-10-06", 600.0, "工资", "测试备注", true);

        categoryManager = CategoryManager.getInstance();
        categoryManager.reset();
    }

    @After
    public void teardown(){
        categoryManager.reset();
        userManager.reset();
    }

    // 显示所有支出分类
    @Test
    public void showExpenseCategoryTest() throws InterruptedException {
        ViewInteraction bottomNavigationItemView = onView(
                allOf(withId(R.id.item_category), withContentDescription("账目分类"),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.bottom_navigation_view),
                                        0),
                                1),
                        isDisplayed()));
        bottomNavigationItemView.perform(click());

        Thread.sleep(1000);
        ViewInteraction tabView = onView(
                allOf(withContentDescription("支出"),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.tab_book_keep_type),
                                        0),
                                0),
                        isDisplayed()));
        tabView.perform(click());

        // 断言视图内容是否显示了支出分类
        mActivityScenarioRule.getScenario().onActivity(activity -> {
            CategoryFragment fragment = (CategoryFragment) activity.getSupportFragmentManager()
                    .findFragmentByTag("f" + 1);
            assert fragment != null;
            View rootView = fragment.getView();
            assert rootView!= null;
            RecyclerView recyclerView = rootView.findViewById(R.id.recyclerView_category);
            assert recyclerView!= null;
            assert recyclerView.getAdapter()!= null;
            assert recyclerView.getAdapter().getItemCount() == 2;
            for (int i = 0; i < recyclerView.getAdapter().getItemCount(); i++) {
                TextView textView = recyclerView.getChildAt(i).findViewById(R.id.tv_category);
                assert textView!= null;
                assert textView.getText().toString().equals(categoryManager.getExpenseCategoryList().get(i));
            }
        });
    }

    // 显示所有收入分类
    @Test
    public void showIncomeCategoryTest() throws InterruptedException {
        ViewInteraction bottomNavigationItemView = onView(
                allOf(withId(R.id.item_category), withContentDescription("账目分类"),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.bottom_navigation_view),
                                        0),
                                1),
                        isDisplayed()));
        bottomNavigationItemView.perform(click());

        Thread.sleep(1000);
        ViewInteraction tabView = onView(
                allOf(withContentDescription("收入"),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.tab_book_keep_type),
                                        0),
                                1),
                        isDisplayed()));
        tabView.perform(click());

        // 断言视图内容是否显示了收入分类
        mActivityScenarioRule.getScenario().onActivity(activity -> {
            CategoryFragment fragment = (CategoryFragment) activity.getSupportFragmentManager()
                   .findFragmentByTag("f" + 1);
            assert fragment!= null;
            View rootView = fragment.getView();
            assert rootView!= null;
            RecyclerView recyclerView = rootView.findViewById(R.id.recyclerView_category);
            assert recyclerView!= null;
            assert recyclerView.getAdapter()!= null;
            assert recyclerView.getAdapter().getItemCount() == 2;
            for (int i = 0; i < recyclerView.getAdapter().getItemCount(); i++) {
                TextView textView = recyclerView.getChildAt(i).findViewById(R.id.tv_category);
                assert textView!= null;
                assert textView.getText().toString().equals(categoryManager.getIncomeCategoryList().get(i));
            }
        });
    }

    // 显示所有餐饮分类的支出账目
    @Test
    public void showExpenseByCategoryTest() throws InterruptedException {
        showExpectedBookKeep(R.id.radioButton_expense, "支出", 2);

        // 断言视图内容是否显示了所有支出分类、餐饮分类的账目
        mActivityScenarioRule.getScenario().onActivity(activity -> {
            BookkeepFragment fragment = (BookkeepFragment) activity.getSupportFragmentManager()
                    .findFragmentByTag("f" + 2);
            assert fragment!= null;
            View rootView = fragment.getView();
            assert rootView!= null;

            // 断言 Spinner 中的所有 item 和预期一致（所有的支出分类）
            Spinner spinner = activity.findViewById(R.id.spinner_category);
            assert spinner != null;
            SpinnerAdapter adapter = spinner.getAdapter();
            assert adapter != null;
            ArrayList<String> expectedItems = new ArrayList<>(Arrays.asList("全部", "出行", "餐饮"));
            assert adapter.getCount() == expectedItems.size();
            for (int i = 0; i < adapter.getCount(); i++) {
                String actualItem = (String) adapter.getItem(i);
                assert actualItem != null;
                assert actualItem.equals(expectedItems.get(i));
            }

            // 断言 RecyclerView 中的所有 item 和预期一致（记账类型为支出，分类为餐饮）
            RecyclerView recyclerView = rootView.findViewById(R.id.recyclerView_record);
            assert recyclerView!= null;
            assert recyclerView.getAdapter()!= null;
            assert recyclerView.getAdapter().getItemCount() == 2;
            for (int i = 0; i < recyclerView.getAdapter().getItemCount(); i++) {
                TextView textView = recyclerView.getChildAt(i).findViewById(R.id.tv_category);
                assert textView!= null;
                assert textView.getText().toString().equals("餐饮");
                textView = recyclerView.getChildAt(i).findViewById(R.id.tv_type);
                assert textView!= null;
                assert textView.getText().toString().equals("支出");
            }
        });
    }

    // 显示所有工资分类的收入账目
    @Test
    public void showIncomeByCategoryTest() throws InterruptedException {
        showExpectedBookKeep(R.id.radioButton_income, "收入", 1);

        // 断言视图内容是否显示了所有收入分类、工资分类的账目
        mActivityScenarioRule.getScenario().onActivity(activity -> {
            BookkeepFragment fragment = (BookkeepFragment) activity.getSupportFragmentManager()
                    .findFragmentByTag("f" + 2);
            assert fragment!= null;
            View rootView = fragment.getView();
            assert rootView!= null;

            // 断言 Spinner 中的所有 item 和预期一致（所有的支出分类）
            Spinner spinner = activity.findViewById(R.id.spinner_category);
            assert spinner != null;
            SpinnerAdapter adapter = spinner.getAdapter();
            assert adapter != null;
            ArrayList<String> expectedItems = new ArrayList<>(Arrays.asList("全部", "工资", "奖金"));
            assert adapter.getCount() == expectedItems.size();
            for (int i = 0; i < adapter.getCount(); i++) {
                String actualItem = (String) adapter.getItem(i);
                assert actualItem != null;
                assert actualItem.equals(expectedItems.get(i));
            }

            // 断言 RecyclerView 中的所有 item 和预期一致（记账类型为支出，分类为餐饮）
            RecyclerView recyclerView = rootView.findViewById(R.id.recyclerView_record);
            assert recyclerView!= null;
            assert recyclerView.getAdapter()!= null;
            assert recyclerView.getAdapter().getItemCount() == 3;
            for (int i = 0; i < recyclerView.getAdapter().getItemCount(); i++) {
                TextView textView = recyclerView.getChildAt(i).findViewById(R.id.tv_category);
                assert textView!= null;
                assert textView.getText().toString().equals("工资");
                textView = recyclerView.getChildAt(i).findViewById(R.id.tv_type);
                assert textView!= null;
                assert textView.getText().toString().equals("收入");
            }
        });
    }

    // 进入到账户管理界面，然后选择收支类型和收支分类
    private static void showExpectedBookKeep(int radioButton_expense, String type, int position) throws InterruptedException {
        ViewInteraction bottomNavigationItemView = onView(
                allOf(withId(R.id.item_bookkeep), withContentDescription("账目管理"),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.bottom_navigation_view),
                                        0),
                                3),
                        isDisplayed()));
        bottomNavigationItemView.perform(click());

        Thread.sleep(1000);

        ViewInteraction appCompatRadioButton = onView(
                allOf(withId(radioButton_expense), withText(type),
                        childAtPosition(
                                allOf(withId(R.id.radioGroup_type),
                                        childAtPosition(
                                                withId(R.id.searchBar),
                                                1)),
                                position),
                        isDisplayed()));
        appCompatRadioButton.perform(click());

        Thread.sleep(500);

        ViewInteraction appCompatSpinner = onView(
                allOf(withId(R.id.spinner_category),
                        childAtPosition(
                                childAtPosition(
                                        withId(R.id.searchBar),
                                        2),
                                0),
                        isDisplayed()));
        appCompatSpinner.perform(click());

        DataInteraction appCompatTextView = onData(anything())
                .inAdapterView(childAtPosition(
                        withClassName(is("android.widget.PopupWindow$PopupBackgroundView")),
                        0))
                .atPosition(position);
        appCompatTextView.perform(click());

        Thread.sleep(500);
    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position) {

        return new TypeSafeMatcher<View>() {
            @Override
            public void describeTo(Description description) {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view) {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }
}
